// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraCheatManager.h"
#include "GameFramework/Pawn.h"
#include "LyraPlayerController.h"
#include "LyraDebugCameraController.h"
#include "Engine/Engine.h"
#include "Engine/GameViewportClient.h"
#include "Engine/Console.h"
#include "GameFramework/HUD.h"
#include "System/LyraAssetManager.h"
#include "System/LyraGameData.h"
#include "LyraGameplayTags.h"
#include "AbilitySystem/LyraAbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "Character/LyraHealthComponent.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "System/LyraSystemStatics.h"
#include "Development/LyraDeveloperSettings.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraCheatManager) // 包含由UE生成的代码

DEFINE_LOG_CATEGORY(LogLyraCheat); // 定义日志类别

namespace LyraCheat
{
	static const FName NAME_Fixed = FName(TEXT("Fixed")); // 固定摄像机模式名称
	
	static bool bEnableDebugCameraCycling = false; // 是否启用调试摄像机循环
	static FAutoConsoleVariableRef CVarEnableDebugCameraCycling( // 控制台变量：启用调试摄像机循环
		TEXT("LyraCheat.EnableDebugCameraCycling"),
		bEnableDebugCameraCycling,
		TEXT("如果为true，则可以在运行游戏时循环切换调试摄像机。"),
		ECVF_Cheat);

	static bool bStartInGodMode = false; // 是否开始时启用上帝模式
	static FAutoConsoleVariableRef CVarStartInGodMode( // 控制台变量：开始时启用上帝模式
		TEXT("LyraCheat.StartInGodMode"),
		bStartInGodMode,
		TEXT("如果为true，则会在游戏开始时应用上帝作弊。"),
		ECVF_Cheat);
};

/**
 * 构造函数，设置调试摄像机控制器类。
 */
ULyraCheatManager::ULyraCheatManager()
{
	DebugCameraControllerClass = ALyraDebugCameraController::StaticClass(); // 设置调试摄像机控制器类
}

/**
 * 初始化作弊管理器。
 */
void ULyraCheatManager::InitCheatManager()
{
	Super::InitCheatManager(); // 调用父类初始化

#if WITH_EDITOR
	if (GIsEditor) // 在编辑器环境下
	{
		APlayerController* PC = GetOuterAPlayerController(); // 获取外部玩家控制器
		for (const FLyraCheatToRun& CheatRow : GetDefault<ULyraDeveloperSettings>()->CheatsToRun) // 遍历开发者设置中要运行的作弊
		{
			if (CheatRow.Phase == ECheatExecutionTime::OnCheatManagerCreated) // 如果在作弊管理器创建时执行
			{
				PC->ConsoleCommand(CheatRow.Cheat, /*bWriteToLog=*/ true); // 执行控制台命令
			}
		}
	}
#endif

	if (LyraCheat::bStartInGodMode) // 如果设置了开始时启用上帝模式
	{
		God();	// 调用上帝模式作弊
	}
}

/**
 * 将文本输出到控制台和日志。
 */
void ULyraCheatManager::CheatOutputText(const FString& TextToOutput)
{
#if USING_CHEAT_MANAGER
	// 输出到控制台。
	if (GEngine && GEngine->GameViewport && GEngine->GameViewport->ViewportConsole)
	{
		GEngine->GameViewport->ViewportConsole->OutputText(TextToOutput);
	}

	// 输出到日志。
	UE_LOG(LogLyraCheat, Display, TEXT("%s"), *TextToOutput);
#endif // USING_CHEAT_MANAGER
}

/**
 * 在服务器上为拥有玩家运行作弊命令。
 */
void ULyraCheatManager::Cheat(const FString& Msg)
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
		LyraPC->ServerCheat(Msg.Left(128)); // 在服务器上执行作弊命令（限制前128个字符）
	}
}

/**
 * 在服务器上为所有玩家运行作弊命令。
 */
void ULyraCheatManager::CheatAll(const FString& Msg)
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
		LyraPC->ServerCheatAll(Msg.Left(128)); // 在服务器上为所有玩家执行作弊命令（限制前128个字符）
	}
}

/**
 * 开始下一场比赛。
 */
void ULyraCheatManager::PlayNextGame()
{
	ULyraSystemStatics::PlayNextGame(this); // 调用系统静态函数开始下一场比赛
}

/**
 * 启用调试摄像机。
 */
void ULyraCheatManager::EnableDebugCamera()
{
	Super::EnableDebugCamera(); // 调用父类启用调试摄像机
}

/**
 * 禁用调试摄像机。
 */
void ULyraCheatManager::DisableDebugCamera()
{
	FVector DebugCameraLocation; // 调试摄像机位置
	FRotator DebugCameraRotation; // 调试摄像机旋转

	ADebugCameraController* DebugCC = Cast<ADebugCameraController>(GetOuter()); // 获取调试摄像机控制器
	APlayerController* OriginalPC = nullptr; // 原始玩家控制器

	if (DebugCC)
	{
		OriginalPC = DebugCC->OriginalControllerRef; // 获取原始控制器引用
		DebugCC->GetPlayerViewPoint(DebugCameraLocation, DebugCameraRotation); // 获取玩家视角
	}

	Super::DisableDebugCamera(); // 调用父类禁用调试摄像机

	if (OriginalPC && OriginalPC->PlayerCameraManager && (OriginalPC->PlayerCameraManager->CameraStyle == LyraCheat::NAME_Fixed)) // 如果原始控制器存在且摄像机模式为固定
	{
		OriginalPC->SetInitialLocationAndRotation(DebugCameraLocation, DebugCameraRotation); // 设置初始位置和旋转

		OriginalPC->PlayerCameraManager->ViewTarget.POV.Location = DebugCameraLocation; // 设置视图目标位置
		OriginalPC->PlayerCameraManager->ViewTarget.POV.Rotation = DebugCameraRotation; // 设置视图目标旋转
		OriginalPC->PlayerCameraManager->PendingViewTarget.POV.Location = DebugCameraLocation; // 设置待定视图目标位置
		OriginalPC->PlayerCameraManager->PendingViewTarget.POV.Rotation = DebugCameraRotation; // 设置待定视图目标旋转
	}
}

/**
 * 检查是否在调试摄像机中。
 */
bool ULyraCheatManager::InDebugCamera() const
{
	return (Cast<ADebugCameraController>(GetOuter()) ? true : false); // 如果外部对象是调试摄像机控制器则返回true
}

/**
 * 启用固定摄像机。
 */
void ULyraCheatManager::EnableFixedCamera()
{
	const ADebugCameraController* DebugCC = Cast<ADebugCameraController>(GetOuter()); // 获取调试摄像机控制器
	APlayerController* PC = (DebugCC ? ToRawPtr(DebugCC->OriginalControllerRef) : GetOuterAPlayerController()); // 获取玩家控制器

	if (PC && PC->PlayerCameraManager) // 如果玩家控制器和摄像机管理器存在
	{
		PC->SetCameraMode(LyraCheat::NAME_Fixed); // 设置摄像机模式为固定
	}
}

/**
 * 禁用固定摄像机。
 */
void ULyraCheatManager::DisableFixedCamera()
{
	const ADebugCameraController* DebugCC = Cast<ADebugCameraController>(GetOuter()); // 获取调试摄像机控制器
	APlayerController* PC = (DebugCC ? ToRawPtr(DebugCC->OriginalControllerRef) : GetOuterAPlayerController()); // 获取玩家控制器

	if (PC && PC->PlayerCameraManager) // 如果玩家控制器和摄像机管理器存在
	{
		PC->SetCameraMode(NAME_Default); // 设置摄像机模式为默认
	}
}

/**
 * 检查是否在固定摄像机中。
 */
bool ULyraCheatManager::InFixedCamera() const
{
	const ADebugCameraController* DebugCC = Cast<ADebugCameraController>(GetOuter()); // 获取调试摄像机控制器
	const APlayerController* PC = (DebugCC ? ToRawPtr(DebugCC->OriginalControllerRef) : GetOuterAPlayerController()); // 获取玩家控制器

	if (PC && PC->PlayerCameraManager) // 如果玩家控制器和摄像机管理器存在
	{
		return (PC->PlayerCameraManager->CameraStyle == LyraCheat::NAME_Fixed); // 返回摄像机样式是否为固定
	}

	return false; // 默认返回false
}

/**
 * 切换固定摄像机。
 */
void ULyraCheatManager::ToggleFixedCamera()
{
	if (InFixedCamera()) // 如果在固定摄像机中
	{
		DisableFixedCamera(); // 禁用固定摄像机
	}
	else
	{
		EnableFixedCamera(); // 启用固定摄像机
	}
}

/**
 * 循环切换调试摄像机。
 */
void ULyraCheatManager::CycleDebugCameras()
{
	if (!LyraCheat::bEnableDebugCameraCycling) // 如果未启用调试摄像机循环
	{
		return; // 直接返回
	}
	
	if (InDebugCamera()) // 如果在调试摄像机中
	{
		EnableFixedCamera(); // 启用固定摄像机
		DisableDebugCamera(); // 禁用调试摄像机
	}
	else if (InFixedCamera()) // 如果在固定摄像机中
	{
		DisableFixedCamera(); // 禁用固定摄像机
		DisableDebugCamera(); // 禁用调试摄像机
	}
	else // 如果不在任何特殊摄像机中
	{
		EnableDebugCamera(); // 启用调试摄像机
		DisableFixedCamera(); // 禁用固定摄像机
	}
}

/**
 * 循环切换技能系统调试信息。
 */
void ULyraCheatManager::CycleAbilitySystemDebug()
{
	APlayerController* PC = Cast<APlayerController>(GetOuterAPlayerController()); // 获取玩家控制器

	if (PC && PC->MyHUD) // 如果玩家控制器和HUD存在
	{
		if (!PC->MyHUD->bShowDebugInfo || !PC->MyHUD->DebugDisplay.Contains(TEXT("AbilitySystem"))) // 如果未显示调试信息或未包含技能系统
		{
			PC->MyHUD->ShowDebug(TEXT("AbilitySystem")); // 显示技能系统调试信息
		}

		PC->ConsoleCommand(TEXT("AbilitySystem.Debug.NextCategory")); // 执行控制台命令切换到下一个调试类别
	}
}

/**
 * 取消所有已激活的技能。
 */
void ULyraCheatManager::CancelActivatedAbilities()
{
	if (ULyraAbilitySystemComponent* LyraASC = GetPlayerAbilitySystemComponent()) // 获取玩家技能系统组件
	{
		const bool bReplicateCancelAbility = true; // 设置复制取消技能
		LyraASC->CancelInputActivatedAbilities(bReplicateCancelAbility); // 取消输入激活的技能
	}
}

/**
 * 向自身添加标签。
 */
void ULyraCheatManager::AddTagToSelf(FString TagName)
{
	FGameplayTag Tag = LyraGameplayTags::FindTagByString(TagName, true); // 通过字符串查找游戏标签
	if (Tag.IsValid()) // 如果标签有效
	{
		if (ULyraAbilitySystemComponent* LyraASC = GetPlayerAbilitySystemComponent()) // 获取玩家技能系统组件
		{
			LyraASC->AddDynamicTagGameplayEffect(Tag); // 添加动态标签游戏效果
		}
	}
	else
	{
		UE_LOG(LogLyraCheat, Display, TEXT("AddTagToSelf: 找不到匹配 [%s] 的标签。"), *TagName); // 输出警告日志
	}
}

/**
 * 从自身移除标签。
 */
void ULyraCheatManager::RemoveTagFromSelf(FString TagName)
{
	FGameplayTag Tag = LyraGameplayTags::FindTagByString(TagName, true); // 通过字符串查找游戏标签
	if (Tag.IsValid()) // 如果标签有效
	{
		if (ULyraAbilitySystemComponent* LyraASC = GetPlayerAbilitySystemComponent()) // 获取玩家技能系统组件
		{
			LyraASC->RemoveDynamicTagGameplayEffect(Tag); // 移除动态标签游戏效果
		}
	}
	else
	{
		UE_LOG(LogLyraCheat, Display, TEXT("RemoveTagFromSelf: 找不到匹配 [%s] 的标签。"), *TagName); // 输出警告日志
	}
}

/**
 * 对自身造成伤害。
 */
void ULyraCheatManager::DamageSelf(float DamageAmount)
{
	if (ULyraAbilitySystemComponent* LyraASC = GetPlayerAbilitySystemComponent()) // 获取玩家技能系统组件
	{
		ApplySetByCallerDamage(LyraASC, DamageAmount); // 应用由调用者设定的伤害
	}
}

/**
 * 对目标造成伤害。
 */
void ULyraCheatManager::DamageTarget(float DamageAmount)
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
		if (LyraPC->GetNetMode() == NM_Client) // 如果在客户端
		{
			// 自动将作弊命令发送到服务器以便利。
			LyraPC->ServerCheat(FString::Printf(TEXT("DamageTarget %.2f"), DamageAmount)); // 发送作弊命令到服务器
			return;
		}

		FHitResult TargetHitResult; // 目标命中结果
		AActor* TargetActor = GetTarget(LyraPC, TargetHitResult); // 获取目标角色

		if (ULyraAbilitySystemComponent* LyraTargetASC = Cast<ULyraAbilitySystemComponent>(UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(TargetActor))) // 获取目标技能系统组件
		{
			ApplySetByCallerDamage(LyraTargetASC, DamageAmount); // 应用由调用者设定的伤害
		}
	}
}

/**
 * 应用由调用者设定的伤害到指定的技能系统组件。
 */
void ULyraCheatManager::ApplySetByCallerDamage(ULyraAbilitySystemComponent* LyraASC, float DamageAmount)
{
	check(LyraASC); // 检查技能系统组件是否有效

	TSubclassOf<UGameplayEffect> DamageGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DamageGameplayEffect_SetByCaller); // 获取伤害游戏效果类
	FGameplayEffectSpecHandle SpecHandle = LyraASC->MakeOutgoingSpec(DamageGE, 1.0f, LyraASC->MakeEffectContext()); // 创建效果规格句柄

	if (SpecHandle.IsValid()) // 如果效果规格有效
	{
		SpecHandle.Data->SetSetByCallerMagnitude(LyraGameplayTags::SetByCaller_Damage, DamageAmount); // 设置由调用者设定的伤害量
		LyraASC->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get()); // 对自身应用游戏效果规格
	}
}

/**
 * 治疗自身。
 */
void ULyraCheatManager::HealSelf(float HealAmount)
{
	if (ULyraAbilitySystemComponent* LyraASC = GetPlayerAbilitySystemComponent()) // 获取玩家技能系统组件
	{
		ApplySetByCallerHeal(LyraASC, HealAmount); // 应用由调用者设定的治疗
	}
}

/**
 * 治疗目标。
 */
void ULyraCheatManager::HealTarget(float HealAmount)
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
		FHitResult TargetHitResult; // 目标命中结果
		AActor* TargetActor = GetTarget(LyraPC, TargetHitResult); // 获取目标角色

		if (ULyraAbilitySystemComponent* LyraTargetASC = Cast<ULyraAbilitySystemComponent>(UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(TargetActor))) // 获取目标技能系统组件
		{
			ApplySetByCallerHeal(LyraTargetASC, HealAmount); // 应用由调用者设定的治疗
		}
	}
}

/**
 * 应用由调用者设定的治疗到指定的技能系统组件。
 */
void ULyraCheatManager::ApplySetByCallerHeal(ULyraAbilitySystemComponent* LyraASC, float HealAmount)
{
	check(LyraASC); // 检查技能系统组件是否有效

	TSubclassOf<UGameplayEffect> HealGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().HealGameplayEffect_SetByCaller); // 获取治疗游戏效果类
	FGameplayEffectSpecHandle SpecHandle = LyraASC->MakeOutgoingSpec(HealGE, 1.0f, LyraASC->MakeEffectContext()); // 创建效果规格句柄

	if (SpecHandle.IsValid()) // 如果效果规格有效
	{
		SpecHandle.Data->SetSetByCallerMagnitude(LyraGameplayTags::SetByCaller_Heal, HealAmount); // 设置由调用者设定的治疗量
		LyraASC->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get()); // 对自身应用游戏效果规格
	}
}

/**
 * 获取玩家技能系统组件。
 */
ULyraAbilitySystemComponent* ULyraCheatManager::GetPlayerAbilitySystemComponent() const
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
		return LyraPC->GetLyraAbilitySystemComponent(); // 返回Lyra技能系统组件
	}
	return nullptr; // 默认返回空指针
}

/**
 * 自毁伤害。
 */
void ULyraCheatManager::DamageSelfDestruct()
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
 		if (const ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(LyraPC->GetPawn())) // 查找Pawn扩展组件
		{
			if (PawnExtComp->HasReachedInitState(LyraGameplayTags::InitState_GameplayReady)) // 如果已达到游戏准备初始状态
			{
				if (ULyraHealthComponent* HealthComponent = ULyraHealthComponent::FindHealthComponent(LyraPC->GetPawn())) // 查找生命值组件
				{
					HealthComponent->DamageSelfDestruct(); // 调用自毁伤害
				}
			}
		}
	}
}

/**
 * 切换上帝模式。
 */
void ULyraCheatManager::God()
{
	if (ALyraPlayerController* LyraPC = Cast<ALyraPlayerController>(GetOuterAPlayerController())) // 获取Lyra玩家控制器
	{
		if (LyraPC->GetNetMode() == NM_Client) // 如果在客户端
		{
			// 自动将作弊命令发送到服务器以便利。
			LyraPC->ServerCheat(FString::Printf(TEXT("God"))); // 发送作弊命令到服务器
			return;
		}

		if (ULyraAbilitySystemComponent* LyraASC = LyraPC->GetLyraAbilitySystemComponent()) // 获取Lyra技能系统组件
		{
			const FGameplayTag Tag = LyraGameplayTags::Cheat_GodMode; // 获取上帝模式作弊标签
			const bool bHasTag = LyraASC->HasMatchingGameplayTag(Tag); // 检查是否已有该标签

			if (bHasTag) // 如果已有标签
			{
				LyraASC->RemoveDynamicTagGameplayEffect(Tag); // 移除动态标签游戏效果
			}
			else // 如果没有标签
			{
				LyraASC->AddDynamicTagGameplayEffect(Tag); // 添加动态标签游戏效果
			}
		}
	}
}

/**
 * 切换无限生命值模式。
 */
void ULyraCheatManager::UnlimitedHealth(int32 Enabled)
{
	if (ULyraAbilitySystemComponent* LyraASC = GetPlayerAbilitySystemComponent()) // 获取玩家技能系统组件
	{
		const FGameplayTag Tag = LyraGameplayTags::Cheat_UnlimitedHealth; // 获取无限生命值作弊标签
		const bool bHasTag = LyraASC->HasMatchingGameplayTag(Tag); // 检查是否已有该标签

		if ((Enabled == -1) || ((Enabled > 0) && !bHasTag) || ((Enabled == 0) && bHasTag)) // 根据参数决定是否切换
		{
			if (bHasTag) // 如果已有标签
			{
				LyraASC->RemoveDynamicTagGameplayEffect(Tag); // 移除动态标签游戏效果
			}
			else // 如果没有标签
			{
				LyraASC->AddDynamicTagGameplayEffect(Tag); // 添加动态标签游戏效果
			}
		}
	}
}